<script lang="tsx">
import {
  ElTable,
  ElTableColumn,
  ElPagination,
  ComponentSize,
  ElTooltipProps,
  ElConfigProvider
} from 'element-plus'
import { defineComponent, PropType, ref, computed, unref, watch, onMounted, reactive } from 'vue'
import { propTypes } from '@/utils/propTypes'
import zhcn from 'element-plus/dist/locale/zh-cn.mjs'
import type { TableProps, TableColumn, Pagination, TableSetProps } from './types'
import { set, get } from 'lodash-es'
import { CSSProperties } from 'vue'
import { getSlot } from '@/utils/tsxHelper'
import TableActions from './components/TableActions.vue'
import ColumnContent from './components/ColumnContent.vue'
import {IdxTableColumn, SelTableConlumn, renderPreview, getColumn, actionPush} from './components/CustomElement.tsx'
import { CrudSchema, useCrudSchemas } from '@/hooks/web/useCrudSchemas'

export default defineComponent({
  name: 'Table',
  props: {
    pageSize: propTypes.number.def(10),
    currentPage: propTypes.number.def(1),
    // 是否展示表格的工具栏
    showAction: propTypes.bool.def(false),
    // 是否所有的超出隐藏，优先级低于schema中的showOverflowTooltip,
    showOverflowTooltip: propTypes.bool.def(false),
    // 表头
    columns: { type: Array as PropType<TableColumn[]>, default: () => [] },
    // 是否展示分页
    pagination: {type: Object as PropType<Pagination>, default: (): Pagination | undefined => undefined },
    // 仅对 type=selection 的列有效，类型为 Boolean，为 true 则会在数据更新之后保留之前选中的数据（需指定 row-key）
    reserveSelection: propTypes.bool.def(false),
    // 加载状态
    loading: propTypes.bool.def(false),
    // 是否叠加索引
    reserveIndex: propTypes.bool.def(false),
    // 对齐方式
    align: propTypes.string.validate((v: string) => ['left', 'center', 'right'].includes(v)).def('left'),
    // 表头对齐方式
    headerAlign: propTypes.string.validate((v: string) => ['left', 'center', 'right'].includes(v)).def('left'),
    data: {  type: Array as PropType<Recordable[]>,  default: () => []  },
    // 图片自动预览字段数组
    imagePreview: { type: Array as PropType<string[]>, default: () => [] },
    // 视频自动预览字段数组
    videoPreview: { type: Array as PropType<string[]>,  default: () => []  },
    height: propTypes.oneOfType([Number, String]),
    maxHeight: propTypes.oneOfType([Number, String]),
    stripe: propTypes.bool.def(true),
    border: propTypes.bool.def(true),
    size: { type: String as PropType<ComponentSize>, validator: (v: ComponentSize) => ['default', 'small', 'large'].includes(v), default: 'default' },
    fit: propTypes.bool.def(true),
    showHeader: propTypes.bool.def(true),
    highlightCurrentRow: propTypes.bool.def(false),
    currentRowKey: propTypes.oneOfType([Number, String]),
    // row-class-name, 类型为 (row: Recordable, rowIndex: number) => string | string
    rowClassName: { type: [Function, String] as PropType<(row: Recordable, rowIndex: number) => string | string>, default: '' },
    rowStyle: {  type: [Function, Object] as PropType<(row: Recordable, rowIndex: number) => Recordable | CSSProperties>, default: () => undefined },
    cellClassName: {
      type: [Function, String] as PropType<
        (row: Recordable, column: any, rowIndex: number) => string | string
      >,
      default: ''
    },
    cellStyle: {
      type: [Function, Object] as PropType<
        (row: Recordable, column: any, rowIndex: number) => Recordable | CSSProperties
      >,
      default: () => undefined
    },
    headerRowClassName: {
      type: [Function, String] as PropType<(row: Recordable, rowIndex: number) => string | string>,
      default: ''
    },
    headerRowStyle: {
      type: [Function, Object] as PropType<
        (row: Recordable, rowIndex: number) => Recordable | CSSProperties
      >,
      default: () => undefined
    },
    headerCellClassName: {
      type: [Function, String] as PropType<
        (row: Recordable, column: any, rowIndex: number) => string | string
      >,
      default: ''
    },
    headerCellStyle: {
      type: [Function, Object] as PropType<
        (row: Recordable, column: any, rowIndex: number) => Recordable | CSSProperties
      >,
      default: () => undefined
    },
    rowKey: propTypes.string.def('id'),
    emptyText: propTypes.string.def('No Data'),
    defaultExpandAll: propTypes.bool.def(false),
    expandRowKeys: {
      type: Array as PropType<string[]>,
      default: () => []
    },
    defaultSort: {
      type: Object as PropType<{ prop: string; order: string }>,
      default: () => ({})
    },
    tooltipEffect: {
      type: String as PropType<'dark' | 'light'>,
      default: 'dark'
    },
    tooltipOptions: {
      type: Object as PropType<
        Pick<
          ElTooltipProps,
          | 'effect'
          | 'enterable'
          | 'hideAfter'
          | 'offset'
          | 'placement'
          | 'popperClass'
          | 'popperOptions'
          | 'showAfter'
          | 'showArrow'
        >
      >,
      default: () => ({
        enterable: true,
        placement: 'top',
        showArrow: true,
        hideAfter: 200,
        popperOptions: { strategy: 'fixed' }
      })
    },
    showSummary: propTypes.bool.def(false),
    sumText: propTypes.string.def('Sum'),
    summaryMethod: {
      type: Function as PropType<(param: { columns: any[]; data: any[] }) => any[]>,
      default: () => undefined
    },
    spanMethod: {
      type: Function as PropType<
        (param: { row: any; column: any; rowIndex: number; columnIndex: number }) => any[]
      >,
      default: () => undefined
    },
    selectOnIndeterminate: propTypes.bool.def(true),
    indent: propTypes.number.def(16),
    lazy: propTypes.bool.def(false),
    load: {
      type: Function as PropType<(row: Recordable, treeNode: any, resolve: Function) => void>,
      default: () => undefined
    },
    treeProps: {
      type: Object as PropType<{ hasChildren?: string; children?: string; label?: string }>,
      default: () => ({ hasChildren: 'hasChildren', children: 'children', label: 'label' })
    },
    tableLayout: {
      type: String as PropType<'auto' | 'fixed'>,
      default: 'fixed'
    },
    scrollbarAlwaysOn: propTypes.bool.def(false),
    flexible: propTypes.bool.def(false),
    // 自定义内容
    customContent: propTypes.bool.def(false),
    cardBodyStyle: {
      type: Object as PropType<CSSProperties>,
      default: () => ({})
    },
    cardBodyClass: {
      type: String as PropType<string>,
      default: ''
    },
    cardWrapStyle: {
      type: Object as PropType<CSSProperties>,
      default: () => ({})
    },
    cardWrapClass: {
      type: String as PropType<string>,
      default: ''
    }
  },
  emits: ['update:pageSize', 'update:currentPage', 'register', 'refresh'],
  setup(props, { attrs, emit, slots, expose }) {
    const elTableRef = ref<ComponentRef<typeof ElTable>>()
    // 注册
    onMounted(() => {
      const tableRef = unref(elTableRef)
      emit('register', tableRef?.$parent, elTableRef)
    })
    zhcn.el.pagination.goto = '第'


    const pageSizeRef = ref(props.pageSize)

    const currentPageRef = ref(props.currentPage)

    // useTable传入的props
    const outsideProps = ref<TableProps>({})

    const mergeProps = ref<TableProps>({})

    const getProps = computed(() => {
      const propsObj = { ...props }
      Object.assign(propsObj, unref(mergeProps))
      return propsObj
    })
    const setProps = (props: TableProps = {}) => {
      mergeProps.value = Object.assign(unref(mergeProps), props)
      outsideProps.value = { ...props } as any
    }

    const setColumn = (columnProps: TableSetProps[], columnsChildren?: TableColumn[]) => {
      const { columns } = unref(getProps)
      for (const v of columnsChildren || columns) {
        for (const item of columnProps) {
          if (v.field === item.field) {
            set(v, item.path, item.value)
          } else if (v.children?.length) {
            setColumn(columnProps, v.children)
          }
        }
      }
    }

    const addColumn = (column: TableColumn, index?: number) => {
      const { columns } = unref(getProps)
      if (index !== void 0) {
        columns.splice(index, 0, column)
      } else {
        columns.push(column)
      }
    }

    const delColumn = (field: string) => {
      const { columns } = unref(getProps)
      const index = columns.findIndex((item) => item.field === field)
      if (index > -1) {
        columns.splice(index, 1)
      }
    }

    const refresh = () => { emit('refresh')  }

    const changSize = (size: ComponentSize) => { setProps({ size }) }

    const confirmSetColumn = (columns: TableColumn[]) => {  setProps({ columns })  }

    expose({
      setProps,
      setColumn,
      delColumn,
      addColumn,
      elTableRef
    })

    const pagination = computed(() => {
      return Object.assign(
        {
          small: false,
          background: false,
          pagerCount: 6,
          layout: 'total, ->, page, jumper, prev, pager, next,  sizes',
          pageSizes: [10, 20, 30, 40, 50, 100],
          disabled: false,
          hideOnSinglePage: false,
          total: 10
        },
        unref(getProps).pagination
      )
    })

    const actionClick = (type, parm) => {
      actionPush(type, parm);
    }

    watch( () => unref(getProps).pageSize, (val: number) => {
        pageSizeRef.value = val
      })

    watch(() => unref(getProps).currentPage,(val: number) => {
        currentPageRef.value = val
      })

    watch(() => pageSizeRef.value,(val: number) => {
        emit('update:pageSize', val)
      })

    watch( () => currentPageRef.value, (val: number) => {
        emit('update:currentPage', val)
      })

    const getBindValue = computed(() => {
      const bindValue: Recordable = { ...attrs, ...unref(getProps) }
      delete bindValue.columns
      delete bindValue.data
      delete bindValue.align
      return bindValue
    })

    const renderTreeTableColumn = (columnsChildren: TableColumn[]) => {
      const { align, headerAlign, showOverflowTooltip, imagePreview, videoPreview } = unref(getProps)
      return columnsChildren.map((v) => {
        if (v.hidden) return null
        const props = { ...v } as any
        if (props.children) delete props.children

        const children = v.children

        const slots = {
          default: (...args: any[]) => {
            const data = args[0]
            let isPreview = false
            isPreview =
              imagePreview.some((item) => (item as string) === v.field) ||
              videoPreview.some((item) => (item as string) === v.field)

            return children && children.length
              ? renderTreeTableColumn(children)
              : props?.slots?.default
                ? props.slots.default(...args)
                : v?.formatter
                  ? v?.formatter?.(data.row, data.column, get(data.row, v.field), data.$index)
                  : isPreview
                    ? renderPreview(get(data.row, v.field), v.field, imagePreview, videoPreview)
                    : get(data.row, v.field)
          }
        }
        if (props?.slots?.header) {
          slots['header'] = (...args: any[]) => props.slots.header(...args)
        }

        return (
          <ElTableColumn
            showOverflowTooltip={showOverflowTooltip}
            align={align}
            headerAlign={headerAlign}
            {...props}
            prop={v.field}
          >
            {slots}
          </ElTableColumn>
        )
      })
    }

    const renderTableColumn = (columnsChildren?: TableColumn[]) => {
      const {
        columns,
        reserveIndex,
        pageSize,
        currentPage,
        align,
        headerAlign,
        showOverflowTooltip,
        reserveSelection,
        imagePreview,
        videoPreview
      } = unref(getProps)

      return (columnsChildren || columns).map((v) => {
        if (v.hidden) return null
          const props = { ...v } as any
          if (props.children) delete props.children

          const children = v.children

          const slots = {
            default: (...args: any[]) => {
              const data = args[0]

              let isPreview = false
              isPreview =
                imagePreview.some((item) => (item as string) === v.field) ||
                videoPreview.some((item) => (item as string) === v.field)

              return children && children.length
                ? renderTreeTableColumn(children)
                : props?.slots?.default
                    ? props.slots.default(...args)
                    : v?.formatter
                        ? v?.formatter?.(data.row, data.column, get(data.row, v.field), data.$index)
                        : isPreview
                            ? renderPreview(get(data.row, v.field), v.field, imagePreview, videoPreview)
                            : getColumn(data.row, v)
            }
          }
          if (props?.slots?.header) {
            slots['header'] = (...args: any[]) => props.slots.header(...args)
          }

          return (
              <>
                <ElTableColumn
                  showOverflowTooltip={showOverflowTooltip}
                  align={align}
                  headerAlign={headerAlign}
                  {...props}
                  prop={v.field}
                >
                  {slots}
                </ElTableColumn>
             </>
          )

      })
    }

    return () => {
      const tableSlots = {}
      if (getSlot(slots, 'empty')) {
        tableSlots['empty'] = (...args: any[]) => getSlot(slots, 'empty', args)
      }
      if (getSlot(slots, 'append')) {
        tableSlots['append'] = (...args: any[]) => getSlot(slots, 'append', args)
      }
        // 自定义头部的函数
      const renderHeader = () => (
            <TableActions
                columns={unref(getProps).columns}
                onChangSize={changSize}
                onRefresh={refresh}
                onConfirm={confirmSetColumn}
            />
        );
        const headercolumnsetting = ()=>{
            return ( <ElTableColumn class-name="columnsetting" fixed="right" align="right" width="20px" renderHeader={renderHeader} />)
        }

      return (
        <div v-loading={unref(getProps).loading}>
            {unref(getProps).pagination ? (
                <ElConfigProvider v-model:locale={zhcn}>
                <ElPagination
                    v-model:pageSize={pageSizeRef.value}
                    v-model:currentPage={currentPageRef.value}
                    class="mt-10px"
                    {...unref(pagination)}
                ></ElPagination></ElConfigProvider>
            ) : undefined}
          {unref(getProps).customContent ? (
            <ColumnContent
                data={unref(getProps).data}
                class={unref(getProps).cardWrapClass}
                style={unref(getProps).cardWrapStyle}
                bodyClass={unref(getProps).cardBodyClass}
                bodyStyle={unref(getProps).cardBodyStyle}
            />
          ) : (
            <>
              <ElTable  ref={elTableRef} data={unref(getProps).data} {...unref(getBindValue)}>
                {SelTableConlumn()}
                {IdxTableColumn()}
                {renderTableColumn()}
                {headercolumnsetting()}
                {{...tableSlots}}
              </ElTable>
            </>
          )}

        </div>
      )
    }
  }
})
</script>
<style lang="less">

.el-table--default th.el-table__cell:hover{
      border-left: 1px solid #d9d9d9;
      border-right: 1px solid #d9d9d9;
}
.el-table.is-scrolling-left.el-table--border .el-table-fixed-column--left.is-last-column.el-table__cell {
     border-right: 1px solid transparent;
}
.el-table--border .el-table__cell {
     /*border-right: 1px solid rgb(0 0 0 / 0%)*/
    border-left: none;
    border-right: none;
}
.el-table td.el-table__cell, .el-table th.el-table__cell.is-leaf {
    border-bottom: 1px solid #d9d9d9;
}

.el-table th.el-table__cell.is-leaf {
    border-top: 1px solid #d9d9d9;
}
.el-table {
    /*--el-table-border-color: rgb(0 0 0 / 0%);*/
    --el-table-header-bg-color: #f4f4f4;
    /*--el-table-border: 1px solid rgb(0 0 0 / 0%);*/
}
  .el-table td.el-table__cell .cell  {
    white-space: nowrap;
  }
  .table-col-link{
    color: var(--el-color-primary);
  }
.table-col-link:hover{
  color: #4069FF;
  cursor: pointer;
}
  .el-table-column--selection .cell{
      margin-left:-7px !important;
  }
  .columnsetting::before{
      box-shadow: none !important;
  }

  .el-table__body .columnsetting{
      width: 0px !important;
  }

  .el-table__header .columnsetting .cell{
      padding: 0px !important;
  }


.el-table--default {
    font-size: 13px;
}

.el-table--default .el-table__cell {
    padding: 4px 0;
    border-right: 1px solid transparent;
    border-left: 1px solid transparent;
}

.el-table--border .el-table__inner-wrapper::after, .el-table--border::after, .el-table--border::before, .el-table__inner-wrapper::before {
    /*content: "";*/
    /*position: absolute;*/
    background-color: transparent;
    /*z-index: calc(var(--el-table-index) + 2);*/
}
.el-table__border-left-patch{
    width: 0px;
}
.el-pagination {
    --el-pagination-font-size: 13px;

    .el-select {
        width: 100px;
    }
    .el-input--default{
        height: 24px;
        width: 50px;
    }

    .el-pagination__editor {

        .el-input__wrapper {
            padding: 1px 4px;
        }
    }

    .el-select--small .el-select__wrapper {
        gap: 4px;
        padding: 2px 4px;
        min-height: 24px;
        line-height: 20px;
        font-size: 12px;
    }
    .el-select__wrapper{
        box-shadow: none;
        font-size: 13px;
    }
    .el-select__wrapper.is-hovering:not(.is-focused){
        box-shadow: none;
    }
}
</style>
<style scoped>

</style>